﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Collections;
using System.Windows.Controls;
using System.Windows.Media;
using XWord.WPF.ApplicationFramework.Threads;
using System.Windows.Input;
using XWord.WPF.ApplicationFramework.Extensions;
namespace XWord.WPF.ApplicationFramework.Controls
{
    public class ElementlPanel : FrameworkElement
    {
        protected UIElementCollection Children { get; set; }

        public ElementlPanel()
        {
            Children = new UIElementCollection(this, this);
        }

        protected override int VisualChildrenCount
        {
            get
            {
                return Children.Count;
            }
        }

        protected override Visual GetVisualChild(int index)
        {
            return Children[index];
        }
    }

    public class ElementItemsControl : ElementlPanel
    {
        public ElementItemsControl()
        {
            this.Loaded += new RoutedEventHandler(VisualItemsControl_Loaded);
            
        }

        protected ScrollViewer viewer;
        void VisualItemsControl_Loaded(object sender, RoutedEventArgs e)
        {
            viewer = this.Parent as ScrollViewer;
            viewer.ScrollChanged += new ScrollChangedEventHandler(viewer_ScrollChanged);
            //Reflesh();
            this.Loaded -= VisualItemsControl_Loaded;
        }

        protected virtual int GetDisplayIndex()
        {
            var index = 0;
            if (viewer != null)
            {
                index = (int)(viewer.VerticalOffset / height);
            }
            if (ItemsSource != null && index > ItemsSource.Count)
            {
                index = 0;
                viewer.ScrollToTop();
            }
            return index;
        }

        protected virtual int GetDisplayCount()
        {
            var count = 0;
            if (viewer != null)
            {
                count = (int)Math.Ceiling(viewer.RenderSize.Height / height);
            }
            if (ItemsSource != null)
                return Math.Min(count, ItemsSource.Count);
            return count;
        }

        public static readonly RoutedEvent SelectionChangedEvent = ListBox.SelectionChangedEvent.AddOwner(typeof(ElementItemsControl));

        public event SelectionChangedEventHandler SelectionChanged
        {
            add { AddHandler(SelectionChangedEvent, value); }
            remove { RemoveHandler(SelectionChangedEvent, value); }
        }
       
        protected double height = 15;



        void viewer_ScrollChanged(object sender, ScrollChangedEventArgs e)
        {
            Reflesh();
        }

        private void Reflesh()
        {
            if (ItemsSource!=null && ItemsSource.Count==0)  return;
            var index = GetDisplayIndex();
            var count = GetDisplayCount();
            
            for (int i = Children.Count; i < count; i++)
            {
                var content = new ElementListBoxItem();
                content.MouseLeftButtonDown += new MouseButtonEventHandler(content_MouseLeftButtonDown);
                content.ContentTemplate = ItemTemplate;
                Children.Add(content);
            }


            for (int i = 0; i < count; i++)
            {
                var content = Children[i] as ElementListBoxItem;
               
                    if (content != null)
                    {
                        content.Content = ItemsSource[i + index];
                    }
                    if (content.Content == this.SelectedItem)
                    {
                        content.IsSelected = true;
                    }
                    else
                    {
                        content.IsSelected = false;
                    }
                    content.Visibility = Visibility.Visible;
                
            }
            for (int i = count; i < Children.Count; i++)
            {
                var content = Children[i] as ElementListBoxItem;
                if (content != null)
                    content.Visibility = Visibility.Collapsed;
            }
            this.InvalidateMeasure();
        }

        void content_MouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            var item = sender as ElementListBoxItem;
            this.InternalSeletedItem = item;
           
        }

        private void InvokeSelectionChanged(object unselectedItem, object selectedItem)
        {
            var unselectedItems = new List<object>() { unselectedItem };
            var selectedItems = new List<object>() { selectedItem };
            SelectionChangedEventArgs e = new SelectionChangedEventArgs
                (SelectionChangedEvent, unselectedItems, selectedItems);
            e.Source = this;
            this.OnSelectionChanged(e);
        }

        protected virtual void OnSelectionChanged(SelectionChangedEventArgs e)
        {
            base.RaiseEvent(e);
        }

        public DataTemplate ItemTemplate
        {
            get { return (DataTemplate)GetValue(ItemTemplateProperty); }
            set { SetValue(ItemTemplateProperty, value); }
        }

        public static readonly DependencyProperty ItemTemplateProperty =
            DependencyProperty.Register("ItemTemplate", typeof(DataTemplate), typeof(ElementListBox), 
            new UIPropertyMetadata(null));

        public ElementListBoxItem InternalSeletedItem
        {
            get { return (ElementListBoxItem)GetValue(InternalSeletedItemProperty); }
            set { SetValue(InternalSeletedItemProperty, value); }
        }

        public static readonly DependencyProperty InternalSeletedItemProperty =
            DependencyProperty.Register("InternalSeletedItem", typeof(ElementListBoxItem), typeof(ElementItemsControl),
            new UIPropertyMetadata(null, (o, a) =>
            {
                var element = o as ElementItemsControl;
                if (a.NewValue != null)
                {
                    element.SelectedItem = element.InternalSeletedItem.Content;
                    element.InternalSeletedItem.IsSelected = true;
                }
                if (a.OldValue != null)
                {
                    (a.OldValue as ElementListBoxItem).IsSelected = false;
                }
                element.InvokeSelectionChanged(a.OldValue, a.NewValue);
                
            }));

        public object SelectedItem
        {
            get { return (object)GetValue(SelectedItemProperty); }
            set { SetValue(SelectedItemProperty, value); }
        }

        public static readonly DependencyProperty SelectedItemProperty =
            DependencyProperty.Register("SelectedItem", typeof(object), typeof(ElementItemsControl),
            new UIPropertyMetadata(null, (o, a) => {
                var element = o as ElementItemsControl;
                //if (a.NewValue != null)
                //{

                //}
                //item.IsSelected = true;
                //this.Reflesh();
            }));

        

        public IList ItemsSource
        {
            get { return (IList)GetValue(ItemsSourceProperty); }
            set { SetValue(ItemsSourceProperty, value); }
        }

        public static readonly DependencyProperty ItemsSourceProperty =
            DependencyProperty.Register("ItemsSource", typeof(IList), typeof(ElementItemsControl),
                                        new FrameworkPropertyMetadata(default(IList), (o, a) => {
                                            UIThread.BeginInvoke(() => {
                                                var element = o as ElementItemsControl;
                                                element.Reflesh();
                                            });
                                        
                                        }));

    }

    public class ElementListBox : ElementItemsControl
    {
        public ElementListBox()
        {
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            
            if (Children.Count > 0)
            {
                var index = GetDisplayIndex();
                var size = new Size();
                var count = GetDisplayCount();
                for (int i = 0; i < count; i++)
                {
                    size = Children[i].DesiredSize;
                    Children[i].Arrange(new Rect(new Point(0, size.Height * (i + index)),new Size(finalSize.Width,size.Height)));
                }
            }
            return finalSize;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            Size desiredSize = new Size();
            desiredSize.Width = Double.PositiveInfinity;
            availableSize.Height = Double.PositiveInfinity;
            var count = GetDisplayCount();
            if (count > 0)
            {
                for (int i = 0; i < count; i++)
                {
                    Children[i].Measure(availableSize);
                }
                var internalheight = Children[0].DesiredSize.Height;
                desiredSize.Height = Convert.ToDouble(ItemsSource.Count * internalheight);
                desiredSize.Width = availableSize.Width;
                height = internalheight;
            }
            return desiredSize;
        }

    }

    public class ElementListBoxItem:ContentControl
    {
        static ElementListBoxItem()
        {
            DefaultStyleKeyProperty.OverrideMetadata(typeof(ElementListBoxItem),
                new FrameworkPropertyMetadata(typeof(ElementListBoxItem)));
        }

        public bool IsSelected
        {
            get { return (bool)GetValue(IsSelectedProperty); }
            set { SetValue(IsSelectedProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsSelected.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsSelectedProperty =
            DependencyProperty.Register("IsSelected", typeof(bool), typeof(ElementListBoxItem), 
            new UIPropertyMetadata(false));

        
    }
}
